/**
 * 
 */
package com.letoo.dragon.common.utils;

import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;

import cn.jiguang.common.ClientConfig;
import cn.jiguang.common.resp.APIConnectionException;
import cn.jiguang.common.resp.APIRequestException;
import cn.jpush.api.JPushClient;
import cn.jpush.api.push.PushResult;
import cn.jpush.api.push.model.Message;
import cn.jpush.api.push.model.Options;
import cn.jpush.api.push.model.Platform;
import cn.jpush.api.push.model.PushPayload;
import cn.jpush.api.push.model.audience.Audience;
import cn.jpush.api.push.model.audience.AudienceTarget;
import cn.jpush.api.push.model.notification.AndroidNotification;
import cn.jpush.api.push.model.notification.IosNotification;
import cn.jpush.api.push.model.notification.Notification;

/**
 * JPUSH极光推送操作工具类
 * 
 * @author dengjie
 *
 */
public class JPushUtils {

    private static final Logger LOG = LoggerFactory.getLogger(JPushUtils.class);

    /**
     * 公用推送方法
     * 
     * @param payload
     *            推送对象
     * @param masterSecret
     *            jpush masterSecret
     * @param appKey
     *            jpush appkey
     * 
     * @return 推送结果对象
     */
    public static final PushResult sendPush(PushPayload payload, String masterSecret, String appKey) {
        JPushClient jpushClient = new JPushClient(masterSecret, appKey, null, ClientConfig.getInstance());

        PushResult result = null;
        try {
            result = jpushClient.sendPush(payload);
            LOG.info("Got result : " + result);
            LOG.info("Response code : " + result.getResponseCode());

        } catch (APIConnectionException e) {
            // Connection error, should retry later
            LOG.error("Connection error, should retry later", e);

        } catch (APIRequestException e) {
            // Should review the error, and fix the request
            LOG.error("Should review the error, and fix the request", e);
            LOG.info("HTTP Status: " + e.getStatus());
            LOG.info("Error Code: " + e.getErrorCode());
            LOG.info("Error Message: " + e.getErrorMessage());
        }
        return result;
    }

    /**
     * 根据极光推送用户别名进行推送透传消息。别名一般使用在一对一的用户上，每个用户在客户端设备上登录的时候可以设置对应的别名。
     * 
     * @param masterSecret
     *            jpush masterSecret
     * @param appKey
     *            jpush appkey
     * @param alias
     *            别名
     * @param title
     *            标题
     * @param msgContent
     *            推送内容
     * @param extras
     *            附件
     * 
     * @return 推送结果对象
     */
    public static final PushResult sendMsgByAlias(String masterSecret, String appKey, String alias, String title,
            String msgContent, Map<String, String> extras) {
        // For push, all you need do is to build PushPayload object.
        PushPayload payload = buildPushObject_by_alias_messageWithExtras(alias, title, msgContent, extras);
        PushResult result = sendPush(payload, masterSecret, appKey);
        return result;
    }

    public static PushPayload buildPushObject_by_alias_messageWithExtras(String alias, String title, String msgContent,
            Map<String, String> extras) {
        cn.jpush.api.push.model.Message.Builder builder = Message.newBuilder();
        if (StringUtils.isNotBlank(title)) {
            builder.setTitle(title);
        }
        if (!CollectionUtils.isEmpty(extras)) {
            builder.addExtras(extras);
        }
        builder.setMsgContent(msgContent);
        Message msg = builder.build();
        Audience audience = Audience.newBuilder().addAudienceTarget(AudienceTarget.alias(alias)).build();
        return PushPayload.newBuilder().setPlatform(Platform.all()).setAudience(audience).setMessage(msg).build();
    }

    /**
     * 根据极光推送用户Registration ID进行推送透传消息。Registration ID：客户端初始化 JPush 成功后，JPush 服务端会分配一个 Registration ID，作为此设备的标识（同一个手机不同
     * APP 的 Registration ID 是不同的）。开发者可以通过指定具体的 Registration ID 来进行对单一设备的推送。
     * 
     * @param masterSecret
     *            jpush masterSecret
     * @param appKey
     *            jpush appkey
     * @param registrationId
     *            registrationId
     * @param title
     *            标题
     * @param msgContent
     *            推送内容
     * @param extras
     *            附件
     * 
     * @return 推送结果对象
     */
    public static final PushResult sendMsgByRegistrationId(String masterSecret, String appKey, String registrationId,
            String title, String msgContent, Map<String, String> extras) {
        // For push, all you need do is to build PushPayload object.
        PushPayload payload = buildPushObject_by_registrationId_messageWithExtras(registrationId, title, msgContent,
                extras);
        PushResult result = sendPush(payload, masterSecret, appKey);
        return result;
    }

    public static PushPayload buildPushObject_by_registrationId_messageWithExtras(String registrationId, String title,
            String msgContent, Map<String, String> extras) {
        cn.jpush.api.push.model.Message.Builder builder = Message.newBuilder();
        if (StringUtils.isNotBlank(title)) {
            builder.setTitle(title);
        }
        if (!CollectionUtils.isEmpty(extras)) {
            builder.addExtras(extras);
        }
        builder.setMsgContent(msgContent);
        Message msg = builder.build();
        Audience audience = Audience.newBuilder().addAudienceTarget(AudienceTarget.registrationId(registrationId))
                .build();
        return PushPayload.newBuilder().setPlatform(Platform.all()).setAudience(audience).setMessage(msg).build();
    }

    /**
     * 根据极光推送用户的Tag进行推送透传消息。tag：为安装了应用程序的用户打上标签，其目的主要是方便开发者根据标签，来批量下发 Push 消息。可为每个用户打多个标签。举例： game, old_page, women
     * 
     * @param masterSecret
     *            jpush masterSecret
     * @param appKey
     *            jpush appkey
     * @param tag
     *            用户分类tag
     * @param title
     *            标题
     * @param msgContent
     *            推送内容
     * @param extras
     *            附件
     * 
     * @return 推送结果对象
     */
    public static final PushResult sendMsgByTag(String masterSecret, String appKey, String tag, String title,
            String msgContent, Map<String, String> extras) {
        // For push, all you need do is to build PushPayload object.
        PushPayload payload = buildPushObject_by_tag_messageWithExtras(tag, title, msgContent, extras);
        PushResult result = sendPush(payload, masterSecret, appKey);
        return result;
    }

    public static PushPayload buildPushObject_by_tag_messageWithExtras(String tag, String title, String msgContent,
            Map<String, String> extras) {
        cn.jpush.api.push.model.Message.Builder builder = Message.newBuilder();
        if (StringUtils.isNotBlank(title)) {
            builder.setTitle(title);
        }
        if (!CollectionUtils.isEmpty(extras)) {
            builder.addExtras(extras);
        }
        builder.setMsgContent(msgContent);
        Message msg = builder.build();
        Audience audience = Audience.newBuilder().addAudienceTarget(AudienceTarget.tag(tag)).build();
        return PushPayload.newBuilder().setPlatform(Platform.all()).setAudience(audience).setMessage(msg).build();
    }

    /*******/

    /**
     * 根据极光推送用户别名进行推送通知。别名一般使用在一对一的用户上，每个用户在客户端设备上登录的时候可以设置对应的别名。
     * 
     * @param masterSecret
     *            jpush masterSecret
     * @param appKey
     *            jpush appkey
     * @param alias
     *            别名
     * @param title
     *            标题
     * @param msgContent
     *            推送内容
     * @param extras
     *            附件
     * 
     * @return 推送结果对象
     */
    public static final PushResult sendNotificationByAlias(String masterSecret, String appKey, String alias,
            String title, String sound, String msgContent, Map<String, String> extras) {
        // For push, all you need do is to build PushPayload object.
        PushPayload payload = buildPushObject_by_alias_notificationWithExtras(alias, title, sound, msgContent, extras);
        PushResult result = sendPush(payload, masterSecret, appKey);
        return result;
    }

    public static PushPayload buildPushObject_by_alias_notificationWithExtras(String alias, String title, String sound,
            String msgContent, Map<String, String> extras) {
        cn.jpush.api.push.model.notification.Notification.Builder builder = Notification.newBuilder();
        // 创建android 的PlatformNotification
        cn.jpush.api.push.model.notification.IosNotification.Builder iosNotificationBuilder = IosNotification
                .newBuilder();
        if (StringUtils.isNotBlank(title)) {
            iosNotificationBuilder.setAlert(title);
        }
        if (StringUtils.isNotBlank(sound)) {
            iosNotificationBuilder.setSound(sound);
        }
        if (!CollectionUtils.isEmpty(extras)) {
            iosNotificationBuilder.addExtras(extras);
        }
        builder.addPlatformNotification(iosNotificationBuilder.build());

        // 创建android 的PlatformNotification
        cn.jpush.api.push.model.notification.AndroidNotification.Builder androidNotificationBuilder = AndroidNotification
                .newBuilder();
        if (StringUtils.isNotBlank(title)) {
            androidNotificationBuilder.setAlert(title);
        }
        if (!CollectionUtils.isEmpty(extras)) {
            androidNotificationBuilder.addExtras(extras);
        }
        builder.addPlatformNotification(androidNotificationBuilder.build());

        Notification notification = builder.build();
        Audience audience = Audience.newBuilder().addAudienceTarget(AudienceTarget.alias(alias)).build();
        return PushPayload.newBuilder().setPlatform(Platform.all()).setAudience(audience).setNotification(notification)
                .setOptions(Options.newBuilder().setApnsProduction(true).build()).build();
    }

    /**
     * 根据极光推送用户Registration ID进行推送通知。Registration ID：客户端初始化 JPush 成功后，JPush 服务端会分配一个 Registration ID，作为此设备的标识（同一个手机不同
     * APP 的 Registration ID 是不同的）。开发者可以通过指定具体的 Registration ID 来进行对单一设备的推送。
     * 
     * @param masterSecret
     *            jpush masterSecret
     * @param appKey
     *            jpush appkey
     * @param registrationId
     *            registrationId
     * @param title
     *            标题
     * @param msgContent
     *            推送内容
     * @param extras
     *            附件
     * 
     * @return 推送结果对象
     */
    public static final PushResult sendNotificationByRegistrationId(String masterSecret, String appKey,
            String registrationId, String title, String sound, String msgContent, Map<String, String> extras) {
        // For push, all you need do is to build PushPayload object.
        PushPayload payload = buildPushObject_by_registrationId_notificationWithExtras(registrationId, title, sound,
                msgContent, extras);
        PushResult result = sendPush(payload, masterSecret, appKey);
        return result;
    }

    public static PushPayload buildPushObject_by_registrationId_notificationWithExtras(String registrationId,
            String title, String sound, String msgContent, Map<String, String> extras) {
        cn.jpush.api.push.model.notification.Notification.Builder builder = Notification.newBuilder();
        // 创建android 的PlatformNotification
        cn.jpush.api.push.model.notification.IosNotification.Builder iosNotificationBuilder = IosNotification
                .newBuilder();
        if (StringUtils.isNotBlank(title)) {
            iosNotificationBuilder.setAlert(title);
        }
        if (StringUtils.isNotBlank(sound)) {
            iosNotificationBuilder.setSound(sound);
        }
        if (!CollectionUtils.isEmpty(extras)) {
            iosNotificationBuilder.addExtras(extras);
        }
        builder.addPlatformNotification(iosNotificationBuilder.build());

        // 创建android 的PlatformNotification
        cn.jpush.api.push.model.notification.AndroidNotification.Builder androidNotificationBuilder = AndroidNotification
                .newBuilder();
        if (StringUtils.isNotBlank(title)) {
            androidNotificationBuilder.setAlert(title);
        }
        if (!CollectionUtils.isEmpty(extras)) {
            androidNotificationBuilder.addExtras(extras);
        }
        builder.addPlatformNotification(androidNotificationBuilder.build());

        Notification notification = builder.build();
        Audience audience = Audience.newBuilder().addAudienceTarget(AudienceTarget.registrationId(registrationId))
                .build();
        return PushPayload.newBuilder().setPlatform(Platform.all()).setAudience(audience).setNotification(notification)
                .setOptions(Options.newBuilder().setApnsProduction(true).build()).build();
    }

    /**
     * 根据极光推送用户的Tag进行推送通知。tag：为安装了应用程序的用户打上标签，其目的主要是方便开发者根据标签，来批量下发 Push 消息。可为每个用户打多个标签。举例： game, old_page, women
     * 
     * @param masterSecret
     *            jpush masterSecret
     * @param appKey
     *            jpush appkey
     * @param tag
     *            用户分类tag
     * @param title
     *            标题
     * @param msgContent
     *            推送内容
     * @param extras
     *            附件
     * 
     * @return 推送结果对象
     */
    public static final PushResult sendNotificationByTag(String masterSecret, String appKey, String tag, String title,
            String sound, String msgContent, Map<String, String> extras) {
        // For push, all you need do is to build PushPayload object.
        PushPayload payload = buildPushObject_by_tag_notificationWithExtras(tag, title, sound, msgContent, extras);
        PushResult result = sendPush(payload, masterSecret, appKey);
        return result;
    }

    public static PushPayload buildPushObject_by_tag_notificationWithExtras(String tag, String title, String sound,
            String msgContent, Map<String, String> extras) {
        cn.jpush.api.push.model.notification.Notification.Builder builder = Notification.newBuilder();
        // 创建android 的PlatformNotification
        cn.jpush.api.push.model.notification.IosNotification.Builder iosNotificationBuilder = IosNotification
                .newBuilder();
        if (StringUtils.isNotBlank(title)) {
            iosNotificationBuilder.setAlert(title);
        }
        if (StringUtils.isNotBlank(sound)) {
            iosNotificationBuilder.setSound(sound);
        }
        if (!CollectionUtils.isEmpty(extras)) {
            iosNotificationBuilder.addExtras(extras);
        }
        builder.addPlatformNotification(iosNotificationBuilder.build());

        // 创建android 的PlatformNotification
        cn.jpush.api.push.model.notification.AndroidNotification.Builder androidNotificationBuilder = AndroidNotification
                .newBuilder();
        if (StringUtils.isNotBlank(title)) {
            androidNotificationBuilder.setAlert(title);
        }
        if (!CollectionUtils.isEmpty(extras)) {
            androidNotificationBuilder.addExtras(extras);
        }
        builder.addPlatformNotification(androidNotificationBuilder.build());

        Notification notification = builder.build();
        Audience audience = Audience.newBuilder().addAudienceTarget(AudienceTarget.tag(tag)).build();
        return PushPayload.newBuilder().setPlatform(Platform.all()).setAudience(audience).setNotification(notification)
                .setOptions(Options.newBuilder().setApnsProduction(true).build()).build();
    }
}
